/**
 ******************************************************************************
 * @file           : main.c
 * @brief          : I2C EEPROM Example
 ******************************************************************************
 * @attention
 *
 * I2C和EEPROM读写示例
 * 功能：
 *   - I2C初始化
 *   - EEPROM读取
 *   - EEPROM写入
 *   - 数据验证
 *
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "stm32h7xx.h"
#include <stdio.h>
#include <string.h>

/* Private defines -----------------------------------------------------------*/
#define EEPROM_ADDR     0xA0
#define EEPROM_SIZE     256

/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;
uint8_t eeprom_buffer[EEPROM_SIZE];
uint8_t test_data[EEPROM_SIZE];

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
void i2c_init(void);
void usart_init(uint32_t baudrate);
void usart_send_byte(uint8_t byte);
void eeprom_read(uint16_t addr, uint8_t *data, uint16_t len);
void eeprom_write(uint16_t addr, uint8_t *data, uint16_t len);
uint8_t eeprom_verify(uint16_t addr, uint8_t *data, uint16_t len);

/* Private functions ---------------------------------------------------------*/

/**
 * @brief       USART初始化
 *
 * @param[in]   baudrate - 波特率
 *
 * @retval      无
 */
void usart_init(uint32_t baudrate)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    UART_HandleTypeDef huart1 = {0};

    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_USART1_CLK_ENABLE();

    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_10;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    huart1.Instance = USART1;
    huart1.Init.BaudRate = baudrate;
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
    huart1.Init.StopBits = UART_STOPBITS_1;
    huart1.Init.Parity = UART_PARITY_NONE;
    huart1.Init.Mode = UART_MODE_TX_RX;
    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
    huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
    huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;

    HAL_UART_Init(&huart1);
}

/**
 * @brief       发送单字节
 *
 * @param[in]   byte - 要发送的字节
 *
 * @retval      无
 */
void usart_send_byte(uint8_t byte)
{
    while(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TXE) == RESET);
    USART1->TDR = byte;
}

/**
 * @brief       printf重定向
 *
 * @param[in]   ch - 字符
 * @param[in]   f - 文件指针
 *
 * @retval      int - 字符
 */
int fputc(int ch, FILE *f)
{
    usart_send_byte((uint8_t)ch);
    return ch;
}

/**
 * @brief       I2C初始化
 *
 * @param       无
 *
 * @retval      无
 */
void i2c_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_I2C1_CLK_ENABLE();

    /* 配置I2C引脚 */
    GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* 配置I2C */
    hi2c1.Instance = I2C1;
    hi2c1.Init.Timing = 0x00B03FDB;  /* 400kHz */
    hi2c1.Init.OwnAddress1 = 0;
    hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
    hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
    hi2c1.Init.OwnAddress2 = 0;
    hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
    hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;

    HAL_I2C_Init(&hi2c1);
    HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE);
    HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0);
}

/**
 * @brief       EEPROM读取
 *
 * @param[in]   addr - 地址
 * @param[out]  data - 数据缓冲区
 * @param[in]   len - 长度
 *
 * @retval      无
 */
void eeprom_read(uint16_t addr, uint8_t *data, uint16_t len)
{
    uint8_t addr_buf[2] = {(addr >> 8) & 0xFF, addr & 0xFF};

    HAL_I2C_Master_Transmit(&hi2c1, EEPROM_ADDR, addr_buf, 2, 1000);
    HAL_I2C_Master_Receive(&hi2c1, EEPROM_ADDR, data, len, 1000);
}

/**
 * @brief       EEPROM写入
 *
 * @param[in]   addr - 地址
 * @param[in]   data - 数据缓冲区
 * @param[in]   len - 长度
 *
 * @retval      无
 */
void eeprom_write(uint16_t addr, uint8_t *data, uint16_t len)
{
    uint8_t buf[258];

    buf[0] = (addr >> 8) & 0xFF;
    buf[1] = addr & 0xFF;
    memcpy(&buf[2], data, len);

    HAL_I2C_Master_Transmit(&hi2c1, EEPROM_ADDR, buf, len + 2, 1000);
    HAL_Delay(10);  /* 等待写入完成 */
}

/**
 * @brief       EEPROM验证
 *
 * @param[in]   addr - 地址
 * @param[in]   data - 数据缓冲区
 * @param[in]   len - 长度
 *
 * @retval      uint8_t - 1=成功, 0=失败
 */
uint8_t eeprom_verify(uint16_t addr, uint8_t *data, uint16_t len)
{
    uint8_t read_data[EEPROM_SIZE];

    eeprom_read(addr, read_data, len);

    for(uint16_t i = 0; i < len; i++)
    {
        if(read_data[i] != data[i])
        {
            return 0;
        }
    }

    return 1;
}

/**
 * @brief       系统时钟配置
 *
 * @param       无
 *
 * @retval      无
 */
void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM = 5;
    RCC_OscInitStruct.PLL.PLLN = 160;
    RCC_OscInitStruct.PLL.PLLP = 2;
    RCC_OscInitStruct.PLL.PLLQ = 4;
    RCC_OscInitStruct.PLL.PLLR = 2;
    RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL_RANGE_VCO_250_500M;
    RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL_VCORANGE_WIDE;
    RCC_OscInitStruct.PLL.PLLFRACN = 0;
    HAL_RCC_OscConfig(&RCC_OscInitStruct);

    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
                                  | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
    HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4);
}

/**
 * @brief       主函数
 *
 * @param       无
 *
 * @retval      int
 */
int main(void)
{
    /* 初始化 */
    HAL_Init();
    SystemClock_Config();
    usart_init(115200);
    i2c_init();

    /* 打印欢迎信息 */
    printf("\r\n");
    printf("================================\r\n");
    printf("STM32H7xx I2C EEPROM Example\r\n");
    printf("================================\r\n");
    printf("EEPROM Address: 0x%02X\r\n", EEPROM_ADDR);
    printf("EEPROM Size: %d bytes\r\n", EEPROM_SIZE);
    printf("\r\n");

    /* 初始化测试数据 */
    for(int i = 0; i < EEPROM_SIZE; i++)
    {
        test_data[i] = i & 0xFF;
    }

    /* 写入EEPROM */
    printf("Writing EEPROM...\r\n");
    eeprom_write(0x0000, test_data, EEPROM_SIZE);
    printf("EEPROM written!\r\n\r\n");

    /* 读取EEPROM */
    printf("Reading EEPROM...\r\n");
    eeprom_read(0x0000, eeprom_buffer, EEPROM_SIZE);
    printf("EEPROM read!\r\n\r\n");

    /* 验证数据 */
    printf("Verifying data...\r\n");
    if(eeprom_verify(0x0000, test_data, EEPROM_SIZE))
    {
        printf("Data verification: PASSED!\r\n");
    }
    else
    {
        printf("Data verification: FAILED!\r\n");
    }

    printf("\r\n");

    /* 主循环 */
    while(1)
    {
        printf("EEPROM test completed!\r\n");
        HAL_Delay(2000);
    }

    return 0;
}

/**
 * @brief       系统异常处理
 *
 * @param       无
 *
 * @retval      无
 */
void HardFault_Handler(void)
{
    while(1)
    {
        HAL_Delay(100);
    }
}
